#pragma once

#include <string>
#include <thread>
#include <map>
#include <unordered_map>
#include <curl/curl.h>
#include <openssl/hmac.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>
#include <nlohmann/json.hpp>
#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>
#include "fmtlog.h"

using client = websocketpp::client<websocketpp::config::asio_tls_client>;
using context_ptr = std::shared_ptr<boost::asio::ssl::context>;
using websocketpp::lib::bind;
using websocketpp::lib::placeholders::_1;
using message_ptr = websocketpp::config::asio_client::message_type::ptr;

class BinanceAccount {
public:
    static BinanceAccount* getInstance(const std::string& api_key,const std::string& secret_key);
    void connect();
    double getBalance(const std::string& coin);
    void initBalance(const std::map<std::string,double>& balances);

protected:
    void run_account_client();
    void keep_user_stream();
    void on_account_message(websocketpp::connection_hdl hdl, message_ptr msg);
    void on_account_open(websocketpp::connection_hdl hdl);
    void on_account_close(websocketpp::connection_hdl hdl);
    std::string getSinnature(const std::string& data);
    static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp);
    void getListenKey();
    void putListenKey();

private:
    std::map<std::string,double> coinBalance;

    std::string apiKey;
    std::string secretKey;
    std::string userStreamKey;
    client m_account_client;
   
    static BinanceAccount* account;
    BinanceAccount(const std::string& api_key,const std::string& secret_key);
};
